Skip to content

perf(rocm): head_dim=128 decode arm -- the ROCm half of #382, default OFF - #767

Merged
localai-bot merged 3 commits into
mudler:mainfrom
joral:row/ROCM-DECODE-ATTN-D128-IMPL
Aug 17, 2026
Merged

perf(rocm): head_dim=128 decode arm -- the ROCm half of #382, default OFF#767
localai-bot merged 3 commits into
mudler:mainfrom
joral:row/ROCM-DECODE-ATTN-D128-IMPL

Conversation

@joral

@joral joral commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Implements .agents/specs/rocm-decode-attn-d128.md, which landed ahead of this change as #564.

The ROCm half of #382. The CUDA half merged as #425 (66399617); this mirrors it, adopting that arm's flag, default and stated reason rather than inventing new ones.

What changes

d == 128 — the Qwen3-dense / Llama / Mistral head size — reaches the fast decode kernels instead of falling through to the generic PagedAttnOnline. LoadRowEplBf16/StoreRowEplBf16 gain an EPL=4 (uint2) case beside the existing EPL=8/16; the dispatch gates and the two launch switches gain a d == 128 arm. No new kernel and no new algorithm — the kernel bodies were already generic over EPL.

Default OFF, opt in with VT_ATTN_DECODE_D128=1 — the same env var, default and reason as the merged CUDA arm. The arm is correctness-complete but not byte-exact against the kernel it replaces: warp-strided online softmax reduces the KV sequence in a different order than PagedAttnOnline's per-tile loop, so a greedy anchor can move at an exact bf16 tie. Shipping OFF keeps every existing golden byte-identical. The flip owes the near-tie razor, a distributional gate and regen under the ratified-tie rule, and per the spec must be argued per backend — see the reversal below. That is what keeps #382 open.

Reviewer note

Spec §4 item 3 writes the gate as (d == 128 && (decode_d128 || decode_wmma)). This commit implements it without the decode_wmma disjunct, which is what the same item's "Forward reference" paragraph instructs: VT_ATTN_DECODE_WMMA does not exist in the tree, and the flag lands with the rocWMMA arm on its own branch. The difference is intentional; it is visible in the diff before the note explaining it is.

Evidence

gfx1200 (RX 9060 XT, RDNA4, 32 CU), ROCm 7.2.3, $GPU_LOCK held. All figures are a same-binary flag A/B — no rebuild between arms — at 1024-token synthetic prompt, 128 generated, greedy, seed 0, 2 reps per cell agreeing within ~1%.

Model head_dim decode path TPOT OFF TPOT ON speedup
Qwen3-0.6B 128 qg=2 fused 42.53 ms 11.78 ms 3.61x
Qwen3-1.7B 128 qg=2 fused 52.85 ms 21.93 ms 2.41x
Qwen3-4B 128 qg=4 per-head 81.89 ms 39.22 ms 2.09x
Qwen3.5-0.8B 256 — (control) 23.76 ms 23.55 ms 1.01x

Qwen3-4B has no GQA fusion at any head_dim, so its 2.09x isolates the EPL widening from the fusion.

Qwen3.5-0.8B is the negative control and it earned its keep. Its head_dim is 256, so the d == 128 gate provably cannot reach it. Its first OFF rep came in a 33% outlier at 31.14 ms, which a blind 2-rep average would have reported as a ~1.2x "win" for a model the flag cannot affect. Re-run three times: 23.86 / 23.75 / 23.68 against ON's 23.52 / 23.57.

End-to-end output throughput rises less than TPOT on the same runs (0.6B 2.48x, 1.7B 2.05x, 4B 2.02x) because they carry a 1024-token prefill the flag does not touch. TPOT isolates decode; throughput dilutes it.

Concurrency — the advantage grows, it does not compress

Qwen3-1.7B, --num-prompts = 2x concurrency:

Conc tok/s OFF tok/s ON ratio TPOT ratio
1 12.89 24.66 1.91x 2.40x
2 23.27 47.45 2.04x 2.45x
4 39.10 86.86 2.22x 2.46x
8 58.97 147.35 2.50x 2.77x
16 78.43 227.08 2.90x 3.18x

This refuted the prediction made before the run, which reasoned that a tiny grid at concurrency 1 flatters the fast kernel. The dominant effect is the reverse: from c8 to c16 the fallback scales only 1.33x against the arm's 1.54x, and scaling efficiency at c16 relative to perfect-linear-from-c1 is 38% OFF against 58% ON. PagedAttnOnline is the batch-scaling bottleneck, not merely slow per call, so the win is largest in the regime a server actually runs in.

The c1 row reproduces an independently-run four-model sweep to within ~1% (52.85/21.93 there vs 53.40/22.26 here).

Correctness

  • ctest -R 'rocm|cross_device' 5/5, chained directly to the exact-SHA push.
  • New case: "paged attention at Qwen3 geometry (bf16, GQA 2, head_dim 128) matches the CPU oracle", looped over RegisteredDevices(), NMSE <= 5e-4 vs the CPU oracle plus OpProviderStats::declines == 0. Genuinely new coverage — the existing generic cross-device test runs at d=8, f32 and never reached any bf16 EPL-templated kernel, so none of them had bf16 coverage in this suite. (The merged CUDA arm shipped with no test at all.)
  • Because the arm ships OFF and its flag is read into a static const bool — once per process — the default registration can only ever gate the fallback. tests/CMakeLists.txt adds a second invocation with the flag set, same shape as the existing test_dense_gateup_fused_marlin_off_* pair. Verified non-vacuous against the test_voxtral_e2e reports SUCCESS with zero assertions when its weights env var is unset (and ~40 more gates share the shape) #463 trap: 1 case, 6 assertions, not zero.
  • Full ctest 448/455. The 7 failures are proven pre-existing, not asserted: a clean main 2784dd7b worktree built from source with none of this code fails the identical set (only test_op_parity's index shifts 403 -> 404, from the added registration). They are a missing shellcheck, an mmap-RSS assertion, a JSON type error, and the SharedExpertGate ROCm registration gap owed to unmerged feat(rocm): MoE combine/gate ops — SharedExpertGate, MoeCombine, MoeCombineGate (issue #41) #509.
  • agent-preflight fails 9, a strict subset of that same baseline's 10 (differing only by role-undeclared). check-commit-trailers and check-doc-checkpoint both pass against this base.

Carried finding

#382 measured this same EPL=4 arm 1.6x slower on sm_110 / Jetson AGX Thor, where gfx1200 measures it 2-3.6x faster. Recorded, not reconciled — different kernels, different fallbacks, different memory systems. It is why the default-ON flip must be argued per backend rather than once, and it is preserved in the spec rather than averaged away.

Against the pinned oracle: 6.35x to 1.75x slower on per-token decode

Measured after the tables above, with both sides in the same container, oracle = vLLM 555967922 in its production configuration via vllm bench serve. Qwen3-0.6B, 1024 in / 128 out, concurrency 1, 8 prompts, warmup discarded, 3 reps:

TPOT reps mean vs oracle
ours, flag unset 42.54 / 42.46 / 42.19 42.40 ms 6.35x slower
ours, VT_ATTN_DECODE_D128=1 11.97 / 11.38 / 11.66 11.67 ms 1.75x slower
vLLM 555967922 6.57 / 6.90 / 6.58 6.68 ms

Running our binary against the container's ROCm rather than the host's is a substitution, so it was proved inert first: in-container matches native at 42.79 vs 42.53 ms unset, and 12.03 vs 11.78 ms with the flag.

The prompt count is load-bearing. At --num-prompts 2 the oracle returned TPOT 6.96 ms and 13.45 ms on consecutive reps, a ~2x spread averaging to a plausible-looking and entirely fictional number. At 8 prompts with a discarded warmup both sides hold to ~±0.3 ms.

This number lived only in a PR comment, which a squash merge does not carry into the tree. It is now in the spec's §5 and appended to .agents/benchmark-record.md, with its caveats attached rather than trailing.

The container/glibc blocker was RETRACTED

An earlier revision of this body, and the spec's §6, said the oracle re-measure was blocked on a Nix-glibc vs container-glibc ABI mismatch. That diagnosis was wrong and is retracted. Our binary runs inside the pinned oracle container; the earlier failures were self-inflicted (LD_LIBRARY_PATH exported container-wide, which breaks the container's own tools, plus a bind mount that silently yielded nothing and looked exactly like a missing ELF interpreter). §6 now reads "not run — not blocked", and the WMMA-spec cross-reference is gone. A false blocker in the record is worse than no record, because it stops the next person from trying.

Not claimed

This does not close #488. That issue asks for a per-call kernel comparison and explicitly asserts no cause. The number above is per-token latency with asymmetric harnesses — the oracle over HTTP via vllm bench serve, ours in-process — so TPOT is the only comparable axis, and TTFT, E2EL and end-to-end throughput carry the oracle's HTTP and tokenizer overhead and are directional only. It is not the same-tool per-call trace AGENTS.md wants before a throughput claim. rocprofv3 is present in the container and our binary traces under it; what is still owed is decode-phase windowing on the oracle side, or the trace compares our decode against vLLM's model load and graph capture. One board, one shape. docs/BENCHMARKS.md's ROCm axis stays PENDING, and the row this PR adds is marked DIRECTIONAL and sits beside the existing row rather than overwriting it.

The flag-ON arm still has no proof it REACHES the new kernel, now filed as #1134. RegisteredDevices() (tests/vt/test_backend_cross_device.cpp:84-96) enumerates {kCUDA, kMETAL, kVULKAN, kXPU, kROCM} and excludes kCPU, so on a CPU-only runner — which is what CI has — the new case reports 1 test case, 0 assertions, exit 0, for both registrations. On ROCm the case's only backend assertion is OpProviderStats::declines == 0, counted at provider granularity, so it is identical with the flag set and unset. §9 stop condition 2 is left OPEN. The spec disclosed this honestly; what was missing is the issue AGENTS.md requires for a known gap not fixed in flow. Searched before filing: not a duplicate of #463 (the unset-weights-env-var shape, which does not describe the declines half), #785 (a kernel that never LAUNCHES behind a dead #if) or #900 (same family, LTX-2.5 subject).

Also out of scope and named in the spec's new ## Owed section: the dtype gap (ROCm's decode-opt is bf16-only at every head_dim, so 4 of 5 dtype combinations still fall to PagedAttnOnline at d=128 — pre-existing, inherited, not introduced), qg=4/qg=8 fusion, d=128 prefill, and the rocWMMA arm.

Record repairs carried in the final commit

docs(BACKEND-ROCM): retract the blocker, keep the oracle number, and file the gap, on top of joral's commits, which are untouched. It carries the retraction above; the oracle number into §5 and .agents/benchmark-record.md; docs/BENCHMARKS.md and docs/STATUS.md reconciled; §7's stale "two flag-on ctest registrations" corrected to one, matching what 8aedd780 already fixed in §4 item 3 and the Test-coverage section; a literal ## Owed heading over the owed list; and #1134 filed and appended to .agents/issue-index.md. Two comment-only edits at rocm_paged_attn.hip:330 and :455, which still enumerated "EPL=8 → d=256, EPL=16 → d=512" without the new EPL=4 case although the top-of-file comment at :264 had been updated.

The branch is rebased onto origin/main d1e5e9bc — it was 39 commits behind, and the rebase drops the earlier merge: upstream/main commit. Gates rerun from the worktree with explicit SHAs: check-commit-trailers, check-commit-style, check-doc-checkpoint, check-public-doc-tables, check-agent-record and check-pr-size, all OK. Not rebuilt and not re-run on hardware: every gfx1200 figure here is joral's, unchanged.

Row: BACKEND-ROCM
Issue: #382
Issue: #1134
Spec: #564

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [claude-code]
Assisted-by: ClaudeCode:claude-opus-5 [ClaudeCode]

@joral

joral commented Aug 14, 2026

Copy link
Copy Markdown
Contributor Author

Follow-up: the oracle comparison this PR listed as blocked is no longer blocked, and here is the number

The PR body's "Not claimed" section says the residual gap to vLLM was not re-measured because the same-tool comparison was blocked on a Nix-glibc-vs-container ABI mismatch. That diagnosis was wrong and I'm retracting it. Our binary runs inside the pinned oracle container fine; the earlier failures were self-inflicted (exporting LD_LIBRARY_PATH container-wide, which breaks the container's own tools, plus a bind mount that silently yielded nothing and looked exactly like a missing ELF interpreter).

Sanity check first, since running our binary against the container's ROCm rather than the host's is a substitution worth proving inert — in-container matches native:

Qwen3-0.6B, 1024 in / 128 out, conc 1 native in container
TPOT, flag unset 42.53 ms 42.79 ms
TPOT, VT_ATTN_DECODE_D128=1 11.78 ms 12.03 ms

Both sides in the same container, matched workload (Qwen3-0.6B, 1024 in / 128 out, concurrency 1, 8 prompts, warmup discarded, 3 reps), oracle = vLLM 555967922 in production config via vllm bench serve:

TPOT reps mean vs oracle
ours, flag unset 42.54 / 42.46 / 42.19 42.40 ms 6.35x slower
ours, VT_ATTN_DECODE_D128=1 11.97 / 11.38 / 11.66 11.67 ms 1.75x slower
vLLM 555967922 6.57 / 6.90 / 6.58 6.68 ms

So this arm closes the decode gap from 6.35x to 1.75x against the oracle on this shape.

What this is not

One measurement note worth recording: at --num-prompts 2 the oracle gave TPOT 6.96 ms and 13.45 ms on consecutive reps — a ~2x spread that averages to a plausible-looking and entirely fictional number. The figures above use 8 prompts with a discarded warmup, where both sides hold to ~±0.3 ms.

One stale line on main, if you want it fixed

.agents/specs/rocm-decode-attn-d128.md (merged in #564) says in §6:

…(blocked on the container/glibc issue recorded in the WMMA spec)

That is now false, and it is the kind of line that stops the next person from trying. Happy to send a one-line PR changing it to "not run — not blocked", or to fold it into this PR, or to leave it — your call. The reproduction details are host-specific (nix store paths, local mounts) so I'd keep those out of the repo and only correct the claim.

joral added a commit to joral/vllm.cpp that referenced this pull request Aug 14, 2026
FOLLOWING_AGENTS_PROTOCOL

CI on mudler#767 failed `check-commit-trailers` with "range base must be an ancestor
of range head". Not a trailer defect: main had advanced 39 commits past this
branch's base (2784dd7), so main's tip was no longer an ancestor of the head
and the checker could not form a range at all.

Merged rather than rebased -- this repo's convention (`merge: origin/main into
row/<ID>` appears throughout the history), and it keeps the pushed SHA a
fast-forward instead of needing a force-push.

No conflicts. Both auto-merged test files verified by hand rather than trusted:
the head_dim-128 cross-device case and the VT_ATTN_DECODE_D128 ctest
registration are both present and intact, and main touched neither
rocm_paged_attn.hip nor the d128 dispatch.

Re-gated on the merge result, gfx1200, $GPU_LOCK held: build 599/599,
`ctest -R 'rocm|cross_device'` 5/5 including the flag-on registration.

Row: BACKEND-ROCM
Issue: mudler#382

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [Claude Code]
joral and others added 2 commits August 17, 2026 13:54
…efault OFF

FOLLOWING_AGENTS_PROTOCOL

Implements .agents/specs/rocm-decode-attn-d128.md, committed ahead of this
change.

The ROCm mirror of PR mudler#425's CUDA arm for issue mudler#382. Every fast decode kernel
in rocm_paged_attn.hip was gated to d == 256 || d == 512, so head_dim 128 --
Qwen3-dense, Llama and Mistral -- fell straight through to PagedAttnOnline.
LoadRowEplBf16/StoreRowEplBf16 gain an EPL=4 (uint2) case, and both decode
dispatch switches gain a d == 128 branch, so that geometry reaches
PagedAttnDecodeGqaBf16 (qg=2, fused) or PagedAttnDecodeOptBf16T (per-head)
instead.

Gated VT_ATTN_DECODE_D128, DEFAULT OFF -- the same env var, default and reason
as the merged CUDA arm, because the warp-strided online softmax reduces the KV
sequence in a different ORDER than PagedAttnOnline, so a greedy anchor can move
at an exact bf16 tie and OFF keeps every golden byte-identical. No allowlist
entry is owed: the CUDA arm already added VT_ATTN_DECODE_D128.

Testing: a new bf16 Qwen3-geometry (GQA 2, head_dim 128) cross-device case,
where the suite previously had no bf16 coverage of any EPL-templated kernel.
Because the arm ships OFF and its flag is read into a static const bool -- once
per process -- the default registration can only ever gate the fallback, so
tests/CMakeLists.txt registers a second invocation of the same binary with the
flag set. Verified non-vacuous against the issue mudler#463 trap: 1 case, 6
assertions, not zero.

Scope note: this commit is the SCALAR arm only. The rocWMMA d=128 decode spike
that was originally developed alongside it is split into its own spec and its
own PR -- it is a spike with its own (unfiled) issue, and bundling the two put
474 lines of two unrelated kernels in one review. The `|| decode_wmma` disjunct
in the bf16_decode_opt gate belongs to that change, not this one: it only means
anything once a second opt-in kernel for this head size exists.

Row: BACKEND-ROCM
Issue: mudler#382

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: Claude:claude-sonnet-5 [Claude Code]
Assisted-by: Claude:claude-opus-5 [Claude Code]
…mudler#382)

Review repair on top of joral's commits, which are untouched.

The spec merged as mudler#564 with a banner reading "**Not landed.** ... No
`VT_ATTN_DECODE_D128` exists in `src/vt/rocm/` on `main` --
`git log -S'VT_ATTN_DECODE_D128' -- src/vt/rocm/` is empty". Landing this PR
makes all three clauses false and hands a reader a git command that returns the
opposite of what the spec claims.

That is the MIRROR IMAGE of the finding that blocked mudler#564: that review stopped a
spec claiming work had landed when it had not. This one would have landed the
code and left the spec claiming it had not. Same defect, opposite sign, and the
same consequence -- the record disagreeing with the tree, which AGENTS.md treats
as the thing git exists to prevent.

Four corrections, each verified against the landed diff rather than assumed:

1. The banner now says the arm lands here, and states why the section stays
   `## Result` rather than becoming `## Outcome`: BACKEND-ROCM remains ACTIVE,
   and `## Outcome` is scoped to a row reaching DONE.

2. Section 4's gate was specified as
   `(d == 128 && (decode_d128 || decode_wmma)) || 256 || 512`. As landed the
   `decode_wmma` disjunct is ABSENT, because that flag does not exist anywhere
   in `src/` or `tests/`. Recorded as the deliberate deviation it is, next to
   the forward-reference paragraph that already anticipates it.

3. "Two extra ctest registrations" -> ONE. The planned second,
   `VT_ATTN_DECODE_WMMA=1`, could not land for the same reason.

4. "6/6 pass, including both new flag-on registrations" -> 5/5 with the one
   that exists, with the superseded figure named rather than silently swapped.

WHAT THIS DOES NOT FIX, and now says so in two places. The flag-ON arm has no
proof it REACHES the new kernel. `OpProviderStats` counts at provider
granularity, so the case's `declines == 0` is identical with the flag set and
unset; and because `RegisteredDevices()` excludes kCPU, the case runs 1 test
case and 0 assertions on every non-ROCm machine while exiting 0. So the
registration added to make the arm "actually gated rather than silently
skipped" is green on nothing everywhere this project owns hardware.

Section 9's stop condition 2 -- "stop if the flag-ON arm cannot be shown to
reach the new kernel; confirm selection counts, not just tokens" -- is
therefore still OPEN, and the spec now says that instead of implying the ctest
registrations discharged it. Closing it needs a kernel-selection counter in
`rocm_paged_attn.hip` asserted to differ between the two registrations.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: Claude:claude-opus-5 [Claude Code]
…file the gap (mudler#382)

FOLLOWING_AGENTS_PROTOCOL

Record repair on top of joral's mudler#767. No kernel behaviour changes: the two
`rocm_paged_attn.hip` edits are comments.

FIVE THINGS THE RECORD GOT WRONG OR WOULD HAVE LOST.

1. The spec shipped a blocker its own author had RETRACTED. Section 6 said the
   post-change oracle re-measure was "blocked on the container/glibc issue
   recorded in the WMMA spec". In the mudler#767 comment of 2026-08-14 joral writes
   "That diagnosis was wrong and I'm retracting it": our binary runs inside the
   pinned oracle container, and the failures behind that reading were
   self-inflicted -- LD_LIBRARY_PATH exported container-wide, which breaks the
   container's own tools, plus a bind mount that silently yielded nothing and
   presented as a missing ELF interpreter. Landing it unchanged ships a false
   blocker, and a false blocker is worse than an empty record because it stops
   the next person from trying. Section 6 now reads "not run -- NOT blocked",
   cites the comment, and names what the trace still needs (decode-phase
   windowing on the oracle side, or it compares our decode against vLLM's model
   load and graph capture). The WMMA-spec cross-reference is gone.

2. The strongest evidence in the pull request existed only in a GitHub comment,
   which a squash merge does not carry into the tree. Both sides in the same
   container, oracle = vLLM 555967922 in production configuration via
   `vllm bench serve`, Qwen3-0.6B 1024 in / 128 out, concurrency 1, 8 prompts,
   warmup discarded, 3 reps: ours 42.40 ms unset, 11.67 ms with
   VT_ATTN_DECODE_D128=1, oracle 6.68 ms -- 6.35x to 1.75x slower. Plus the
   in-container-vs-native inertness control (42.53/42.79 and 11.78/12.03).
   Folded into spec section 5 and APPENDED to .agents/benchmark-record.md.

   The caveats travel with the number rather than behind it. This is per-token
   LATENCY with asymmetric harnesses -- the oracle over HTTP, ours in-process
   -- not the same-tool per-call trace AGENTS.md wants before a throughput
   comparison, and it does not close mudler#488, which asks for a per-CALL kernel
   comparison. One board, one shape. docs/BENCHMARKS.md's ROCm axis therefore
   stays PENDING and the new row is marked DIRECTIONAL, not binding; it is
   added BESIDE the existing row rather than overwriting it, so no entry is
   evicted. Also recorded: at --num-prompts 2 the oracle gave 6.96 ms and
   13.45 ms on consecutive reps, a ~2x spread averaging to a plausible-looking
   and entirely fictional number. That is why the table uses 8.

3. The spec contradicted itself on a number. 8aedd78 corrected "two flag-on
   ctest registrations" to ONE in section 4 item 3 and in the Test-coverage
   section, and missed section 7 and the result banner. Both now say one, with
   the reason (VT_ATTN_DECODE_WMMA does not exist).

4. The owed list had no heading a checker or a reader can find. Section 7's
   out-of-scope list is now a literal `## Owed` section, which is the surface
   AGENTS.md and check-agent-record.py read for an issue that names no owning
   row.

5. A KNOWN GAP HAD NO ISSUE. Filed as mudler#1134 and appended to
   .agents/issue-index.md under BACKEND-ROCM. RegisteredDevices()
   (tests/vt/test_backend_cross_device.cpp:84-96) enumerates
   {kCUDA, kMETAL, kVULKAN, kXPU, kROCM} and excludes kCPU, so on a CPU-only
   runner -- which is what CI has -- the new head_dim-128 case reports 1 test
   case, 0 assertions, exit 0, for BOTH registrations. On ROCm hardware the
   case's only backend assertion is OpProviderStats::declines == 0, counted at
   PROVIDER granularity, so it is identical with the flag set and unset. The
   two compose: no machine in this project distinguishes the flag-ON
   registration from the flag-OFF one. The spec disclosed this honestly and
   left section 9 stop condition 2 open, which was right; what was missing is
   that AGENTS.md requires an issue for a known gap not fixed in flow. Searched
   before filing -- mudler#463 is the unset-weights-env-var shape and does not
   describe the declines half, mudler#785 is a kernel that never LAUNCHES behind a
   dead #if, mudler#900 is the same family on LTX-2.5 -- so this is not a duplicate.

The two comment edits are item 6 of the review, non-blocking: the kernel
headers at rocm_paged_attn.hip:330 and :455 still enumerated "EPL=8 -> d=256,
EPL=16 -> d=512" without the new EPL=4 case, although the top-of-file comment
at :264 had been updated. Both now name d=128 and its opt-in flag.

Rebased onto origin/main d1e5e9b, which drops joral's earlier merge commit;
the branch was based 39 commits behind. Gates run from this worktree with
explicit SHAs.

Row: BACKEND-ROCM
Issue: mudler#382
Issue: mudler#1134

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: ClaudeCode:claude-opus-5 [ClaudeCode]
@localai-bot
localai-bot force-pushed the row/ROCM-DECODE-ATTN-D128-IMPL branch from 8aedd78 to e2f6115 Compare August 17, 2026 14:05
@localai-bot
localai-bot merged commit a7583ac into mudler:main Aug 17, 2026
20 of 25 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ROCm gfx1200: PagedAttnOnline is 8.1x slower per call than vLLM's paged-attention kernel (41.1us vs 5.10us)

3 participants